package com.example.framework.common.util.thread;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.nio.charset.Charset;
import java.util.concurrent.*;

@Slf4j
public class ThreadUtils {

    private static final int CORE_SIZE = 50; // Runtime.getRuntime().availableProcessors() * 2

    private static final int MAX_SIZE = CORE_SIZE * 2;

    private static final int CAPACITY = 100;

    private static final ThreadPoolTaskExecutor EXECUTOR = new TTLTraceThreadPoolExecutor(
            CORE_SIZE,
            MAX_SIZE,
            CAPACITY,
            60,
            "commonExe",
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    public static ThreadPoolTaskExecutor getExecutor() {
        return EXECUTOR;
    }

    /**
     * 线程池状态
     */
    public static String getInfo(ExecutorService executor) {
        return StrUtil.str(executor, Charset.defaultCharset());
    }

    public static String getInfo() {
        return StrUtil.str(EXECUTOR, Charset.defaultCharset());
    }

    /**
     * 多线程运行
     */
    public static void run(Runnable runnable) {
        execute(runnable);
    }

    public static void execute(Runnable runnable) {
        EXECUTOR.execute(runnable);
    }

    /**
     * 多线程运行, 获取 future
     */
    public static <T> Future<T> call(Callable<T> callable) {
        return EXECUTOR.submit(callable);
    }

    /**
     * 虚拟线程池相关-生产慎用!
     */
    public static ExecutorService createVirtualThreadExecutor() {
        return createVirtualThreadExecutor("virExe");
    }

    public static ExecutorService createVirtualThreadExecutor(String name) {
        return Executors.newThreadPerTaskExecutor(Thread.ofVirtual().name(name).factory());
    }

    public static void executeWithVirtualThread(Runnable runnable) {
        ThreadUtils.createVirtualThreadExecutor().execute(runnable);
    }

    public static void executeWithVirtualThread(String name, Runnable runnable) {
        ThreadUtils.createVirtualThreadExecutor(name).execute(runnable);
    }

    public static <T> Future<T> callWithVirtualThread(Callable<T> callable) {
        return ThreadUtils.createVirtualThreadExecutor().submit(callable);
    }

    public static <T> Future<T> callWithVirtualThread(String name, Callable<T> callable) {
        return ThreadUtils.createVirtualThreadExecutor(name).submit(callable);
    }

    public static <T> T getFutureResult(Future<T> future) {
        try {
            return future.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
